Included templates
contentlayer-next-docs-page-with-nav
contentlayer-next-docs-page-with-nav
Nav between documents and on page heading elements
Pasted files structure
├── app
│ └── docs
│ └── [[...slug]]
│ ├── layout.tsx
│ └── page.tsx
├── components
│ ├── DocsSideNav.tsx
│ └── PageContentNav.tsx
├── docs
│ ├── Basic use
│ │ ├── Save and Paste.mdx
│ │ └── Scripts.mdx
│ ├── Included scripts
│ │ ├── Add-Contentlayer-docs-nav-template-TS.mdx
│ │ ├── Add-Next-Auth.js-TS.mdx
│ │ ├── Add-Next-RTK-TS.mdx
│ │ ├── Add-ShadcnUI-TS.mdx
│ │ └── Create-Next-ShadcnUI-TS.mdx
│ └── Included templates
│ ├── contentlayer-basic-styled-next-mdx-components.mdx
│ ├── contentlayer-config.mdx
│ ├── contentlayer-next-docs-page-with-nav.mdx
│ ├── contentlayer-next-styled-mdx-components.mdx
│ ├── next-redux-ts.mdx
│ ├── next-shad-darkmode.mdx
│ ├── next13-app-auth-paste-from-root.mdx
│ └── redux-ts.mdx
└── styles
└── docs.css
├── app
│ └── docs
│ └── [[...slug]]
│ ├── layout.tsx
│ └── page.tsx
├── components
│ ├── DocsSideNav.tsx
│ └── PageContentNav.tsx
├── docs
│ ├── Basic use
│ │ ├── Save and Paste.mdx
│ │ └── Scripts.mdx
│ ├── Included scripts
│ │ ├── Add-Contentlayer-docs-nav-template-TS.mdx
│ │ ├── Add-Next-Auth.js-TS.mdx
│ │ ├── Add-Next-RTK-TS.mdx
│ │ ├── Add-ShadcnUI-TS.mdx
│ │ └── Create-Next-ShadcnUI-TS.mdx
│ └── Included templates
│ ├── contentlayer-basic-styled-next-mdx-components.mdx
│ ├── contentlayer-config.mdx
│ ├── contentlayer-next-docs-page-with-nav.mdx
│ ├── contentlayer-next-styled-mdx-components.mdx
│ ├── next-redux-ts.mdx
│ ├── next-shad-darkmode.mdx
│ ├── next13-app-auth-paste-from-root.mdx
│ └── redux-ts.mdx
└── styles
└── docs.css
Files contents
import DocsSideNav from "@/components/DocsSideNav";
import PageContentNav from "@/components/PageContentNav";
import '../../../styles/docs.css'
export default function DocsLayout({ children }: { children: React.ReactNode }) {
return (
<div className="grid grid-cols-[1fr_3fr_1fr] max-w-screen-xl mx-auto mt-10 relative mb-32">
<DocsSideNav />
{children}
<PageContentNav />
</div>
)
}
import DocsSideNav from "@/components/DocsSideNav";
import PageContentNav from "@/components/PageContentNav";
import '../../../styles/docs.css'
export default function DocsLayout({ children }: { children: React.ReactNode }) {
return (
<div className="grid grid-cols-[1fr_3fr_1fr] max-w-screen-xl mx-auto mt-10 relative mb-32">
<DocsSideNav />
{children}
<PageContentNav />
</div>
)
}
import { allDocs } from "@/.contentlayer/generated"
import { Mdx } from "@/components/mdx-components"
import { redirect } from 'next/navigation'
import { MdKeyboardArrowRight } from 'react-icons/md'
const getDocBySlugs = (slugs: string[]) => {
const pathFromSlugs = slugs.join('/')
const doc = allDocs.find((doc) => doc._raw.flattenedPath === pathFromSlugs)
if (!doc) return redirect('/docs/Basic use/Save and Paste')
return doc
}
export default function DocsPage({ params }: { params: { slug?: string[] } }) {
if (!params.slug) return redirect('/docs/Basic use/Save and Paste')
params.slug = params.slug?.map((slug) => decodeURI(slug))
const doc = getDocBySlugs(params.slug)
return (
<article className="min-h-screen pb-8 overflow-x-auto px-8 border-l">
<div className="flex mb-4 gap-1 items-center text-sm">
<p className="text-muted-foreground">{doc._raw.sourceFileDir}</p>
<MdKeyboardArrowRight className="text-muted-foreground" />
<p className="font-medium text-indigo-800 dark:bg-zinc-900 dark:text-indigo-600 bg-indigo-100 px-2 rounded-full">{doc.title}</p>
</div>
<Mdx code={doc?.body.code!} />
</article>
)
}
import { allDocs } from "@/.contentlayer/generated"
import { Mdx } from "@/components/mdx-components"
import { redirect } from 'next/navigation'
import { MdKeyboardArrowRight } from 'react-icons/md'
const getDocBySlugs = (slugs: string[]) => {
const pathFromSlugs = slugs.join('/')
const doc = allDocs.find((doc) => doc._raw.flattenedPath === pathFromSlugs)
if (!doc) return redirect('/docs/Basic use/Save and Paste')
return doc
}
export default function DocsPage({ params }: { params: { slug?: string[] } }) {
if (!params.slug) return redirect('/docs/Basic use/Save and Paste')
params.slug = params.slug?.map((slug) => decodeURI(slug))
const doc = getDocBySlugs(params.slug)
return (
<article className="min-h-screen pb-8 overflow-x-auto px-8 border-l">
<div className="flex mb-4 gap-1 items-center text-sm">
<p className="text-muted-foreground">{doc._raw.sourceFileDir}</p>
<MdKeyboardArrowRight className="text-muted-foreground" />
<p className="font-medium text-indigo-800 dark:bg-zinc-900 dark:text-indigo-600 bg-indigo-100 px-2 rounded-full">{doc.title}</p>
</div>
<Mdx code={doc?.body.code!} />
</article>
)
}
'use client'
import { usePathname } from 'next/navigation'
import { Doc, allDocs } from "@/.contentlayer/generated";
import Link from "next/link";
import { cn } from '@/lib/utils';
export default function DocsSideNav() {
const sortedArr = allDocs.sort((a, b) => a.sortNum - b.sortNum)
const path = decodeURI(usePathname())
const categorizedDocs = sortedArr.reduce((acc: { [key: Doc['_raw']['sourceFileDir']]: Doc[] }, doc) => {
const currCatContent = acc[doc._raw.sourceFileDir]
return {
...acc,
[doc._raw.sourceFileDir]: [...(currCatContent ? currCatContent : []), doc]
}
}, {})
return (
<div className="relative pr-6">
<div className='sticky top-[7.04rem] text-sm'>
{Object.entries(categorizedDocs).map(([cat, docs], i) => {
return (
<div key={i} className="mb-4">
<p className="text-foreground font-semibold mb-2">{cat}</p>
<div className="flex flex-col gap-1">
{docs.map((doc, j) => {
const isActive = path === `/docs/${doc._raw.flattenedPath}`
return <Link key={j} style={{ contain: "inline-size" }} href={`/docs/${doc._raw.flattenedPath}`} className={cn("ml-0 text-muted-foreground hover:text-indigo-700 dark:hover:text-indigo-600 transition-all hover:bg-indigo-50 py-1 px-2 rounded-md text-ellipsis whitespace-nowrap overflow-hidden dark:hover:bg-zinc-900", isActive ? "bg-indigo-50 dark:bg-zinc-900 dark:text-indigo-600 text-indigo-700" : "")}>{doc.title}</Link>
})}
</div>
</div>
)
})}
</div>
</div>
)
}
'use client'
import { usePathname } from 'next/navigation'
import { Doc, allDocs } from "@/.contentlayer/generated";
import Link from "next/link";
import { cn } from '@/lib/utils';
export default function DocsSideNav() {
const sortedArr = allDocs.sort((a, b) => a.sortNum - b.sortNum)
const path = decodeURI(usePathname())
const categorizedDocs = sortedArr.reduce((acc: { [key: Doc['_raw']['sourceFileDir']]: Doc[] }, doc) => {
const currCatContent = acc[doc._raw.sourceFileDir]
return {
...acc,
[doc._raw.sourceFileDir]: [...(currCatContent ? currCatContent : []), doc]
}
}, {})
return (
<div className="relative pr-6">
<div className='sticky top-[7.04rem] text-sm'>
{Object.entries(categorizedDocs).map(([cat, docs], i) => {
return (
<div key={i} className="mb-4">
<p className="text-foreground font-semibold mb-2">{cat}</p>
<div className="flex flex-col gap-1">
{docs.map((doc, j) => {
const isActive = path === `/docs/${doc._raw.flattenedPath}`
return <Link key={j} style={{ contain: "inline-size" }} href={`/docs/${doc._raw.flattenedPath}`} className={cn("ml-0 text-muted-foreground hover:text-indigo-700 dark:hover:text-indigo-600 transition-all hover:bg-indigo-50 py-1 px-2 rounded-md text-ellipsis whitespace-nowrap overflow-hidden dark:hover:bg-zinc-900", isActive ? "bg-indigo-50 dark:bg-zinc-900 dark:text-indigo-600 text-indigo-700" : "")}>{doc.title}</Link>
})}
</div>
</div>
)
})}
</div>
</div>
)
}
'use client'
import { cn } from "@/lib/utils"
import Link from "next/link"
import { useEffect, useState } from "react"
import { Separator } from "./ui/separator"
import { FaStar } from 'react-icons/fa'
import { BsStar } from 'react-icons/bs'
import { HiArrowLongRight } from 'react-icons/hi2'
export default function PageContentNav() {
const [linkedHeadings, setLinkedHeadings] = useState<HTMLAnchorElement[]>([])
const [highlitedHeading, setHighlitedHeading] = useState<HTMLAnchorElement | null>(null)
useEffect(() => {
const lHeadings = document.querySelectorAll(`[aria-label="Link to section"]`)
const mainNav = document.getElementById('main-nav')
console.log("mainNav", mainNav)
lHeadings.forEach((heading) => {
const observer = new IntersectionObserver((entries) => {
console.log("ee", entries)
entries.forEach((entry) => {
if (entry.isIntersecting) {
setHighlitedHeading(heading as HTMLAnchorElement)
}
})
}, { root: null, rootMargin: "0px 0px -80% 0px", threshold: 1 })
observer.observe(heading)
})
setLinkedHeadings(Array.from(lHeadings) as HTMLAnchorElement[])
}, [])
return (
<div style={{ contain: 'strict' }}>
<div className="sticky top-[7.04rem]">
<h3 className="text-sm font-semibold mb-2">On this page</h3>
<div className=" flex flex-col gap-1">
{linkedHeadings?.map((heading, i) => {
return (
<div key={i} className=" w-full">
<a href={heading.href} className={cn("text-sm text-muted-foreground hover:text-indigo-700 transition-all hover:bg-indigo-50 dark:hover:bg-zinc-900 dark:hover:text-indigo-600 py-1 px-2 rounded-md whitespace-nowrap w-full block", heading.href === highlitedHeading?.href ? "text-indigo-700 dark:bg-zinc-900 dark:text-indigo-600 bg-indigo-50" : "")}>
<p className="whitespace-nowrap text-ellipsis overflow-hidden">
{heading.innerText}
</p>
</a>
</div>
)
})}
</div>
<Separator className="mt-6 mb-6" />
<div className="text-muted-foreground text-xs font-medium flex flex-col gap-2 pl-2">
<Link href={'https://github.com/xDepcio/strapup'}>
<div className="flex items-center gap-2 hover:text-indigo-800 dark:hover:text-indigo-600 transition-all">
<p>Star us</p>
<BsStar />
</div>
</Link>
<Link href={'https://github.com/xDepcio/strapup'}>
<div className="flex items-center gap-2 hover:text-indigo-800 dark:hover:text-indigo-600 transition-all">
<p>Contribute</p>
<HiArrowLongRight />
</div>
</Link>
</div>
</div>
</div>
)
}
'use client'
import { cn } from "@/lib/utils"
import Link from "next/link"
import { useEffect, useState } from "react"
import { Separator } from "./ui/separator"
import { FaStar } from 'react-icons/fa'
import { BsStar } from 'react-icons/bs'
import { HiArrowLongRight } from 'react-icons/hi2'
export default function PageContentNav() {
const [linkedHeadings, setLinkedHeadings] = useState<HTMLAnchorElement[]>([])
const [highlitedHeading, setHighlitedHeading] = useState<HTMLAnchorElement | null>(null)
useEffect(() => {
const lHeadings = document.querySelectorAll(`[aria-label="Link to section"]`)
const mainNav = document.getElementById('main-nav')
console.log("mainNav", mainNav)
lHeadings.forEach((heading) => {
const observer = new IntersectionObserver((entries) => {
console.log("ee", entries)
entries.forEach((entry) => {
if (entry.isIntersecting) {
setHighlitedHeading(heading as HTMLAnchorElement)
}
})
}, { root: null, rootMargin: "0px 0px -80% 0px", threshold: 1 })
observer.observe(heading)
})
setLinkedHeadings(Array.from(lHeadings) as HTMLAnchorElement[])
}, [])
return (
<div style={{ contain: 'strict' }}>
<div className="sticky top-[7.04rem]">
<h3 className="text-sm font-semibold mb-2">On this page</h3>
<div className=" flex flex-col gap-1">
{linkedHeadings?.map((heading, i) => {
return (
<div key={i} className=" w-full">
<a href={heading.href} className={cn("text-sm text-muted-foreground hover:text-indigo-700 transition-all hover:bg-indigo-50 dark:hover:bg-zinc-900 dark:hover:text-indigo-600 py-1 px-2 rounded-md whitespace-nowrap w-full block", heading.href === highlitedHeading?.href ? "text-indigo-700 dark:bg-zinc-900 dark:text-indigo-600 bg-indigo-50" : "")}>
<p className="whitespace-nowrap text-ellipsis overflow-hidden">
{heading.innerText}
</p>
</a>
</div>
)
})}
</div>
<Separator className="mt-6 mb-6" />
<div className="text-muted-foreground text-xs font-medium flex flex-col gap-2 pl-2">
<Link href={'https://github.com/xDepcio/strapup'}>
<div className="flex items-center gap-2 hover:text-indigo-800 dark:hover:text-indigo-600 transition-all">
<p>Star us</p>
<BsStar />
</div>
</Link>
<Link href={'https://github.com/xDepcio/strapup'}>
<div className="flex items-center gap-2 hover:text-indigo-800 dark:hover:text-indigo-600 transition-all">
<p>Contribute</p>
<HiArrowLongRight />
</div>
</Link>
</div>
</div>
</div>
)
}
---
title: Save and Paste
sortNum: 1
---
#### How to run It?
To run the Strapup CLI from anywhere on your system, just use:
```command
npx strapup
---
title: Save and Paste
sortNum: 1
---
#### How to run It?
To run the Strapup CLI from anywhere on your system, just use:
```command
npx strapup
This will install required dependencies and correctly setup your enviroment on the first run.
Running for the first time
When you run Strapup for the first time, it will need to perform some setup. For this, you will be asked to provide:
- Path where to create Strapup directory - used to store templates and scripts.
Strapup saves those values in enviroment variables, so on next runs you don't have to provide them again.
Saving and pasting templates
You can save and create templates from within interactive CLI (npx strapup
).
When you paste a template, you will be asked to:
- Choose a template.
- Provide path where to paste - template content will be paste there. Must be a relative path to a directory. If a directory doesn't exist, strapup will be created.
When you save a template, you will be asked to provide:
- Template name and description - used solely for identification purpose.
- Relative path or paths to source directories or files.
- Choose additional
options
:with gitignore
- If selected, files ignored by git will not be included in the template.
Next steps
Running scripts
Leverage the power of scripts to automate your workflow
Premade templates
Use built-in templates to quickly bootstrap your project
```mdx title="./docs/Basic use/Scripts.mdx"
---
title: Scripts
sortNum: 2
---
#### Introduction
Scripts in Strapup are just lists of strings representing shell commands. These commands can also be Strapup instructions like `paste` and `save`. These feature make them very powerfull and can help you automate the process of setting up your projects.
Take one of built-in scripts `nextJsShadcnAuthJs` for example. It setups NextJS 13 app with shadcnUI and Auth.js. You can run It from Strapup CLI (`npx strapup`). Under the hood it will run these commands:
```bash {"1"}
npx create-next-app ${projectName} --typescript --tailwind --eslint --app --no-src-dir --import-alias "@/*"
cd ${projectName}
npx shadcn-ui@latest init -y
npx shadcn-ui@latest add button -y
npx shadcn-ui@latest add input -y
npx shadcn-ui@latest add skeleton -y
npm i next-auth
npx strapup paste next13-app-auth-paste-from-root ./
```mdx title="./docs/Basic use/Scripts.mdx"
---
title: Scripts
sortNum: 2
---
#### Introduction
Scripts in Strapup are just lists of strings representing shell commands. These commands can also be Strapup instructions like `paste` and `save`. These feature make them very powerfull and can help you automate the process of setting up your projects.
Take one of built-in scripts `nextJsShadcnAuthJs` for example. It setups NextJS 13 app with shadcnUI and Auth.js. You can run It from Strapup CLI (`npx strapup`). Under the hood it will run these commands:
```bash {"1"}
npx create-next-app ${projectName} --typescript --tailwind --eslint --app --no-src-dir --import-alias "@/*"
cd ${projectName}
npx shadcn-ui@latest init -y
npx shadcn-ui@latest add button -y
npx shadcn-ui@latest add input -y
npx shadcn-ui@latest add skeleton -y
npm i next-auth
npx strapup paste next13-app-auth-paste-from-root ./
projectName
is entered by user before commands are executed.
Take a look at the last line, which pastes Strapup template to root directory. One script can paste multiple templates or run other Strapup scripts, thus making it possible to create complex projects with one command.
Creating scripts
Scripts can be modified and added by editing scripts.mjs
file located in Strapup directory. You can see its path whenever your running npx strapup
.
Take a look at scripts.mjs
contents:
export const scripts = {
nextJsShadcnAuthJs: {
description: "Create new Next.js typescript, app dir, tailwind, no src dir, shadcn, basic Auth.js",
command: (projectName) => [
`npx create-next-app ${projectName} --typescript --tailwind --eslint --app --no-src-dir --import-alias "@/*"`,
`cd ${projectName}`,
`npx shadcn-ui@latest init -y`,
`npx shadcn-ui@latest add button -y`,
`npx shadcn-ui@latest add input -y`,
`npx shadcn-ui@latest add skeleton -y`,
`npm i next-auth`,
`strapup paste next13-app-auth-paste-from-root ./`,
]
},
// Create a new script by adding a key-value pair based on examples above.
}
export const scripts = {
nextJsShadcnAuthJs: {
description: "Create new Next.js typescript, app dir, tailwind, no src dir, shadcn, basic Auth.js",
command: (projectName) => [
`npx create-next-app ${projectName} --typescript --tailwind --eslint --app --no-src-dir --import-alias "@/*"`,
`cd ${projectName}`,
`npx shadcn-ui@latest init -y`,
`npx shadcn-ui@latest add button -y`,
`npx shadcn-ui@latest add input -y`,
`npx shadcn-ui@latest add skeleton -y`,
`npm i next-auth`,
`strapup paste next13-app-auth-paste-from-root ./`,
]
},
// Create a new script by adding a key-value pair based on examples above.
}
It exports POJO object where keys
- are scripts names, and values
- script informations:
description
- string displayed in Strapup CLI for identification.command
- function, which returns array of strings, which will be executed as shell commands. This function can have any number of parameters and user will be automatically prompted to enter them before script is executed. Parameter name will be displayed in CLI in the prompt.
Next steps
Premade scripts
Use built-in scripts to quickly bootstrap your project
Premade templates
Use built-in templates as building blocks for your project
```mdx title="./docs/Included scripts/Add-Contentlayer-docs-nav-template-TS.mdx"
---
title: Add-Contentlayer-docs-nav-template-TS
sortNum: 1004
---
### Add-Contentlayer-docs-nav-template-TS
Add working contentlayer MDX template to existing NextJS project
### Executed commands
```bash
npm i contentlayer next-contentlayer react-icons react-hot-toast remark-gfm rehype-slug rehype-autolink-headings rehype-pretty-code
npx strapup paste contentlayer-config ./
npx strapup paste contentlayer-next-styled-mdx-components ./
npx strapup paste contentlayer-next-docs-page-with-nav ./
```mdx title="./docs/Included scripts/Add-Contentlayer-docs-nav-template-TS.mdx"
---
title: Add-Contentlayer-docs-nav-template-TS
sortNum: 1004
---
### Add-Contentlayer-docs-nav-template-TS
Add working contentlayer MDX template to existing NextJS project
### Executed commands
```bash
npm i contentlayer next-contentlayer react-icons react-hot-toast remark-gfm rehype-slug rehype-autolink-headings rehype-pretty-code
npx strapup paste contentlayer-config ./
npx strapup paste contentlayer-next-styled-mdx-components ./
npx strapup paste contentlayer-next-docs-page-with-nav ./
```mdx title="./docs/Included scripts/Add-Next-Auth.js-TS.mdx"
---
title: Add-Next-Auth.js-TS
sortNum: 1003
---
### Add-Next-Auth.js-TS
To existing next app, add basic next-auth
### Executed commands
```bash
npm i next-auth
npx strapup paste next13-app-auth-paste-from-root ./
```mdx title="./docs/Included scripts/Add-Next-Auth.js-TS.mdx"
---
title: Add-Next-Auth.js-TS
sortNum: 1003
---
### Add-Next-Auth.js-TS
To existing next app, add basic next-auth
### Executed commands
```bash
npm i next-auth
npx strapup paste next13-app-auth-paste-from-root ./
```mdx title="./docs/Included scripts/Add-Next-RTK-TS.mdx"
---
title: Add-Next-RTK-TS
sortNum: 1001
---
### Add-Next-RTK-TS
Add TS RTK to existing NextJS app
### Executed commands
```bash
npm i @reduxjs/toolkit react-redux
npx strapup paste next-redux-ts ${pasteDir}
```mdx title="./docs/Included scripts/Add-Next-RTK-TS.mdx"
---
title: Add-Next-RTK-TS
sortNum: 1001
---
### Add-Next-RTK-TS
Add TS RTK to existing NextJS app
### Executed commands
```bash
npm i @reduxjs/toolkit react-redux
npx strapup paste next-redux-ts ${pasteDir}
```mdx title="./docs/Included scripts/Add-ShadcnUI-TS.mdx"
---
title: Add-ShadcnUI-TS
sortNum: 1002
---
### Add-ShadcnUI-TS
To existing next app, Shadcn UI add (button, input, skeleton, dropdown), darkmode
### Executed commands
```bash
npx shadcn-ui@latest init -y
npx shadcn-ui@latest add button -y
npx shadcn-ui@latest add input -y
npx shadcn-ui@latest add skeleton -y
npx shadcn-ui@latest add dropdown-menu -y
npm i next-themes
npx strapup paste next-shad-darkmode ./
```mdx title="./docs/Included scripts/Add-ShadcnUI-TS.mdx"
---
title: Add-ShadcnUI-TS
sortNum: 1002
---
### Add-ShadcnUI-TS
To existing next app, Shadcn UI add (button, input, skeleton, dropdown), darkmode
### Executed commands
```bash
npx shadcn-ui@latest init -y
npx shadcn-ui@latest add button -y
npx shadcn-ui@latest add input -y
npx shadcn-ui@latest add skeleton -y
npx shadcn-ui@latest add dropdown-menu -y
npm i next-themes
npx strapup paste next-shad-darkmode ./
```mdx title="./docs/Included scripts/Create-Next-ShadcnUI-TS.mdx"
---
title: Create-Next-ShadcnUI-TS
sortNum: 1000
---
### Create-Next-ShadcnUI-TS
New Next.js app, Shadcn UI add (button, input, skeleton, dropdown), darkmode
### Executed commands
```bash
npx create-next-app ${projectName}
cd ${projectName}
npx strapup run-script Add-ShadcnUI-TS
```mdx title="./docs/Included scripts/Create-Next-ShadcnUI-TS.mdx"
---
title: Create-Next-ShadcnUI-TS
sortNum: 1000
---
### Create-Next-ShadcnUI-TS
New Next.js app, Shadcn UI add (button, input, skeleton, dropdown), darkmode
### Executed commands
```bash
npx create-next-app ${projectName}
cd ${projectName}
npx strapup run-script Add-ShadcnUI-TS
```mdx title="./docs/Included templates/contentlayer-basic-styled-next-mdx-components.mdx"
---
title: contentlayer-basic-styled-next-mdx-components
sortNum: 100
---
### contentlayer-basic-styled-next-mdx-components
#### Pasted files structure
```bash
└── components
└── mdx-components.tsx1 directory, 1 file
```mdx title="./docs/Included templates/contentlayer-basic-styled-next-mdx-components.mdx"
---
title: contentlayer-basic-styled-next-mdx-components
sortNum: 100
---
### contentlayer-basic-styled-next-mdx-components
#### Pasted files structure
```bash
└── components
└── mdx-components.tsx1 directory, 1 file
Files contents
import * as React from "react"
import Image from "next/image"
import { useMDXComponent } from "next-contentlayer/hooks"
import { cn } from "@/lib/utils"
const components = {
h1: ({ className, ...props }: React.ImgHTMLAttributes<HTMLHeadingElement>) => (
<h1
className={cn(
"mt-2 scroll-m-20 text-4xl font-bold tracking-tight",
className
)}
{...props}
/>
),
h2: ({ className, ...props }: React.ImgHTMLAttributes<HTMLHeadingElement>) => (
<h2
className={cn(
"mt-10 scroll-m-20 border-b pb-1 text-3xl font-semibold tracking-tight first:mt-0",
className
)}
{...props}
/>
),
h3: ({ className, ...props }: React.ImgHTMLAttributes<HTMLHeadingElement>) => (
<h3
className={cn(
"mt-8 scroll-m-20 text-2xl font-semibold tracking-tight",
className
)}
{...props}
/>
),
h4: ({ className, ...props }: React.ImgHTMLAttributes<HTMLHeadingElement>) => (
<h4
className={cn(
"mt-8 scroll-m-20 text-xl font-semibold tracking-tight",
className
)}
{...props}
/>
),
h5: ({ className, ...props }: React.ImgHTMLAttributes<HTMLHeadingElement>) => (
<h5
className={cn(
"mt-8 scroll-m-20 text-lg font-semibold tracking-tight",
className
)}
{...props}
/>
),
h6: ({ className, ...props }: React.ImgHTMLAttributes<HTMLHeadingElement>) => (
<h6
className={cn(
"mt-8 scroll-m-20 text-base font-semibold tracking-tight",
className
)}
{...props}
/>
),
a: ({ className, ...props }: React.ImgHTMLAttributes<HTMLAnchorElement>) => (
<a
className={cn("font-medium underline underline-offset-4", className)}
{...props}
/>
),
p: ({ className, ...props }: React.ImgHTMLAttributes<HTMLParagraphElement>) => (
<p
className={cn("leading-7 [&:not(:first-child)]:mt-6", className)}
{...props}
/>
),
ul: ({ className, ...props }: React.ImgHTMLAttributes<HTMLUListElement>) => (
<ul className={cn("my-6 ml-6 list-disc", className)} {...props} />
),
ol: ({ className, ...props }: React.ImgHTMLAttributes<HTMLOListElement>) => (
<ol className={cn("my-6 ml-6 list-decimal", className)} {...props} />
),
li: ({ className, ...props }: React.ImgHTMLAttributes<HTMLLIElement>) => (
<li className={cn("mt-2", className)} {...props} />
),
blockquote: ({ className, ...props }: React.ImgHTMLAttributes<HTMLQuoteElement>) => (
<blockquote
className={cn(
"mt-6 border-l-2 pl-6 italic [&>*]:text-muted-foreground",
className
)}
{...props}
/>
),
img: ({
className,
alt,
...props
}: React.ImgHTMLAttributes<HTMLImageElement>) => (
// eslint-disable-next-line @next/next/no-img-element
<img className={cn("rounded-md border", className)} alt={alt} {...props} />
),
hr: ({ ...props }) => <hr className="my-4 md:my-8" {...props} />,
table: ({ className, ...props }: React.HTMLAttributes<HTMLTableElement>) => (
<div className="my-6 w-full overflow-y-auto">
<table className={cn("w-full", className)} {...props} />
</div>
),
tr: ({ className, ...props }: React.HTMLAttributes<HTMLTableRowElement>) => (
<tr
className={cn("m-0 border-t p-0 even:bg-muted", className)}
{...props}
/>
),
th: ({ className, ...props }: React.ImgHTMLAttributes<HTMLTableCellElement>) => (
<th
className={cn(
"border px-4 py-2 text-left font-bold [&[align=center]]:text-center [&[align=right]]:text-right",
className
)}
{...props}
/>
),
td: ({ className, ...props }: React.ImgHTMLAttributes<HTMLTableCellElement>) => (
<td
className={cn(
"border px-4 py-2 text-left [&[align=center]]:text-center [&[align=right]]:text-right",
className
)}
{...props}
/>
),
pre: ({ className, ...props }: React.ImgHTMLAttributes<HTMLPreElement>) => (
<pre
className={cn(
"mb-4 mt-6 overflow-x-auto rounded-lg border bg-black py-4",
className
)}
{...props}
/>
),
code: ({ className, ...props }: React.ImgHTMLAttributes<HTMLElement>) => (
<code
className={cn(
"relative rounded border px-[0.3rem] py-[0.2rem] font-mono text-sm",
className
)}
{...props}
/>
),
Image,
}
interface MdxProps {
code: string
}
export function Mdx({ code }: MdxProps) {
const Component = useMDXComponent(code)
return (
<div className="mdx">
<Component components={components} />
</div>
)
}
import * as React from "react"
import Image from "next/image"
import { useMDXComponent } from "next-contentlayer/hooks"
import { cn } from "@/lib/utils"
const components = {
h1: ({ className, ...props }: React.ImgHTMLAttributes<HTMLHeadingElement>) => (
<h1
className={cn(
"mt-2 scroll-m-20 text-4xl font-bold tracking-tight",
className
)}
{...props}
/>
),
h2: ({ className, ...props }: React.ImgHTMLAttributes<HTMLHeadingElement>) => (
<h2
className={cn(
"mt-10 scroll-m-20 border-b pb-1 text-3xl font-semibold tracking-tight first:mt-0",
className
)}
{...props}
/>
),
h3: ({ className, ...props }: React.ImgHTMLAttributes<HTMLHeadingElement>) => (
<h3
className={cn(
"mt-8 scroll-m-20 text-2xl font-semibold tracking-tight",
className
)}
{...props}
/>
),
h4: ({ className, ...props }: React.ImgHTMLAttributes<HTMLHeadingElement>) => (
<h4
className={cn(
"mt-8 scroll-m-20 text-xl font-semibold tracking-tight",
className
)}
{...props}
/>
),
h5: ({ className, ...props }: React.ImgHTMLAttributes<HTMLHeadingElement>) => (
<h5
className={cn(
"mt-8 scroll-m-20 text-lg font-semibold tracking-tight",
className
)}
{...props}
/>
),
h6: ({ className, ...props }: React.ImgHTMLAttributes<HTMLHeadingElement>) => (
<h6
className={cn(
"mt-8 scroll-m-20 text-base font-semibold tracking-tight",
className
)}
{...props}
/>
),
a: ({ className, ...props }: React.ImgHTMLAttributes<HTMLAnchorElement>) => (
<a
className={cn("font-medium underline underline-offset-4", className)}
{...props}
/>
),
p: ({ className, ...props }: React.ImgHTMLAttributes<HTMLParagraphElement>) => (
<p
className={cn("leading-7 [&:not(:first-child)]:mt-6", className)}
{...props}
/>
),
ul: ({ className, ...props }: React.ImgHTMLAttributes<HTMLUListElement>) => (
<ul className={cn("my-6 ml-6 list-disc", className)} {...props} />
),
ol: ({ className, ...props }: React.ImgHTMLAttributes<HTMLOListElement>) => (
<ol className={cn("my-6 ml-6 list-decimal", className)} {...props} />
),
li: ({ className, ...props }: React.ImgHTMLAttributes<HTMLLIElement>) => (
<li className={cn("mt-2", className)} {...props} />
),
blockquote: ({ className, ...props }: React.ImgHTMLAttributes<HTMLQuoteElement>) => (
<blockquote
className={cn(
"mt-6 border-l-2 pl-6 italic [&>*]:text-muted-foreground",
className
)}
{...props}
/>
),
img: ({
className,
alt,
...props
}: React.ImgHTMLAttributes<HTMLImageElement>) => (
// eslint-disable-next-line @next/next/no-img-element
<img className={cn("rounded-md border", className)} alt={alt} {...props} />
),
hr: ({ ...props }) => <hr className="my-4 md:my-8" {...props} />,
table: ({ className, ...props }: React.HTMLAttributes<HTMLTableElement>) => (
<div className="my-6 w-full overflow-y-auto">
<table className={cn("w-full", className)} {...props} />
</div>
),
tr: ({ className, ...props }: React.HTMLAttributes<HTMLTableRowElement>) => (
<tr
className={cn("m-0 border-t p-0 even:bg-muted", className)}
{...props}
/>
),
th: ({ className, ...props }: React.ImgHTMLAttributes<HTMLTableCellElement>) => (
<th
className={cn(
"border px-4 py-2 text-left font-bold [&[align=center]]:text-center [&[align=right]]:text-right",
className
)}
{...props}
/>
),
td: ({ className, ...props }: React.ImgHTMLAttributes<HTMLTableCellElement>) => (
<td
className={cn(
"border px-4 py-2 text-left [&[align=center]]:text-center [&[align=right]]:text-right",
className
)}
{...props}
/>
),
pre: ({ className, ...props }: React.ImgHTMLAttributes<HTMLPreElement>) => (
<pre
className={cn(
"mb-4 mt-6 overflow-x-auto rounded-lg border bg-black py-4",
className
)}
{...props}
/>
),
code: ({ className, ...props }: React.ImgHTMLAttributes<HTMLElement>) => (
<code
className={cn(
"relative rounded border px-[0.3rem] py-[0.2rem] font-mono text-sm",
className
)}
{...props}
/>
),
Image,
}
interface MdxProps {
code: string
}
export function Mdx({ code }: MdxProps) {
const Component = useMDXComponent(code)
return (
<div className="mdx">
<Component components={components} />
</div>
)
}
```mdx title="./docs/Included templates/contentlayer-config.mdx"
---
title: contentlayer-config
sortNum: 101
---
### contentlayer-config
#### Pasted files structure
```bash
└── contentlayer.config.ts
```mdx title="./docs/Included templates/contentlayer-config.mdx"
---
title: contentlayer-config
sortNum: 101
---
### contentlayer-config
#### Pasted files structure
```bash
└── contentlayer.config.ts
Files contents
import { defineDocumentType, makeSource } from 'contentlayer/source-files'
import remarkGfm from 'remark-gfm'
import rehypeSlug from 'rehype-slug'
import rehypeAutolinkHeadings from 'rehype-autolink-headings'
import rehypePreetyCode from 'rehype-pretty-code'
export const Doc = defineDocumentType(() => ({
name: 'Doc',
filePathPattern: `**/*.mdx`,
fields: {
title: { type: 'string', required: true },
sortNum: { type: 'number', required: true },
},
computedFields: {
slug: { type: 'string', resolve: (doc) => `/${doc._raw.flattenedPath}` },
slugAsParams: { type: 'string', resolve: (doc) => doc._raw.flattenedPath.split('/').slice(1).join('/') },
},
contentType: 'mdx'
}))
export default makeSource({
contentDirPath: 'docs',
documentTypes: [Doc],
mdx: {
remarkPlugins: [remarkGfm],
rehypePlugins: [
rehypeSlug,
[
rehypePreetyCode,
{
theme: {
light: 'github-light',
dark: 'github-dark'
},
keepBackground: false,
onVisitLine: (node: any) => {
if (node.children.length === 0) {
node.children = [{ type: 'text', value: ' ' }]
}
},
onVisitHighlightedLine: (node: any) => {
node.properties.className.push('line--highlighted')
},
onVisitHighlitedWord: (node: any) => {
node.properties.className = ['word--highlighted']
}
}
],
[
rehypeAutolinkHeadings,
{
behavior: 'wrap',
properties: {
className: ['subheading--anchor'],
ariaLabel: 'Link to section'
}
}
]
]
}
})
import { defineDocumentType, makeSource } from 'contentlayer/source-files'
import remarkGfm from 'remark-gfm'
import rehypeSlug from 'rehype-slug'
import rehypeAutolinkHeadings from 'rehype-autolink-headings'
import rehypePreetyCode from 'rehype-pretty-code'
export const Doc = defineDocumentType(() => ({
name: 'Doc',
filePathPattern: `**/*.mdx`,
fields: {
title: { type: 'string', required: true },
sortNum: { type: 'number', required: true },
},
computedFields: {
slug: { type: 'string', resolve: (doc) => `/${doc._raw.flattenedPath}` },
slugAsParams: { type: 'string', resolve: (doc) => doc._raw.flattenedPath.split('/').slice(1).join('/') },
},
contentType: 'mdx'
}))
export default makeSource({
contentDirPath: 'docs',
documentTypes: [Doc],
mdx: {
remarkPlugins: [remarkGfm],
rehypePlugins: [
rehypeSlug,
[
rehypePreetyCode,
{
theme: {
light: 'github-light',
dark: 'github-dark'
},
keepBackground: false,
onVisitLine: (node: any) => {
if (node.children.length === 0) {
node.children = [{ type: 'text', value: ' ' }]
}
},
onVisitHighlightedLine: (node: any) => {
node.properties.className.push('line--highlighted')
},
onVisitHighlitedWord: (node: any) => {
node.properties.className = ['word--highlighted']
}
}
],
[
rehypeAutolinkHeadings,
{
behavior: 'wrap',
properties: {
className: ['subheading--anchor'],
ariaLabel: 'Link to section'
}
}
]
]
}
})
```mdx title="./docs/Included templates/contentlayer-next-docs-page-with-nav.mdx"
---
title: contentlayer-next-docs-page-with-nav
sortNum: 102
---
### contentlayer-next-docs-page-with-nav
Nav between documents and on page heading elements
#### Pasted files structure
```bash
├── app
│ └── docs
│ └── [[...slug]]
│ ├── layout.tsx
│ └── page.tsx
└── components
└── DocsSideNav.tsx
```mdx title="./docs/Included templates/contentlayer-next-docs-page-with-nav.mdx"
---
title: contentlayer-next-docs-page-with-nav
sortNum: 102
---
### contentlayer-next-docs-page-with-nav
Nav between documents and on page heading elements
#### Pasted files structure
```bash
├── app
│ └── docs
│ └── [[...slug]]
│ ├── layout.tsx
│ └── page.tsx
└── components
└── DocsSideNav.tsx
Files contents
import DocsSideNav from "@/components/DocsSideNav";
import PageContentNav from "@/components/PageContentNav";
import '../../../styles/docs.css'
export default function DocsLayout({ children }: { children: React.ReactNode }) {
return (
<div className="grid grid-cols-[1fr_3fr_1fr] max-w-screen-xl mx-auto mt-10 relative mb-32">
<DocsSideNav />
{children}
<PageContentNav />
</div>
)
}
import DocsSideNav from "@/components/DocsSideNav";
import PageContentNav from "@/components/PageContentNav";
import '../../../styles/docs.css'
export default function DocsLayout({ children }: { children: React.ReactNode }) {
return (
<div className="grid grid-cols-[1fr_3fr_1fr] max-w-screen-xl mx-auto mt-10 relative mb-32">
<DocsSideNav />
{children}
<PageContentNav />
</div>
)
}
import { allDocs } from "@/.contentlayer/generated"
import { Mdx } from "@/components/mdx-components"
import { redirect } from 'next/navigation'
import { MdKeyboardArrowRight } from 'react-icons/md'
const getDocBySlugs = (slugs: string[]) => {
const pathFromSlugs = slugs.join('/')
const doc = allDocs.find((doc) => doc._raw.flattenedPath === pathFromSlugs)
if (!doc) return redirect('/docs/Basic use/Save and Paste')
return doc
}
export default function DocsPage({ params }: { params: { slug?: string[] } }) {
if (!params.slug) return redirect('/docs/Basic use/Save and Paste')
params.slug = params.slug?.map((slug) => decodeURI(slug))
const doc = getDocBySlugs(params.slug)
return (
<article className="min-h-screen pb-8 overflow-x-auto px-8 border-l">
<div className="flex mb-4 gap-1 items-center text-sm">
<p className="text-muted-foreground">{doc._raw.sourceFileDir}</p>
<MdKeyboardArrowRight className="text-muted-foreground" />
<p className="font-medium text-indigo-800 dark:bg-zinc-900 dark:text-indigo-600 bg-indigo-100 px-2 rounded-full">{doc.title}</p>
</div>
<Mdx code={doc?.body.code!} />
</article>
)
}
import { allDocs } from "@/.contentlayer/generated"
import { Mdx } from "@/components/mdx-components"
import { redirect } from 'next/navigation'
import { MdKeyboardArrowRight } from 'react-icons/md'
const getDocBySlugs = (slugs: string[]) => {
const pathFromSlugs = slugs.join('/')
const doc = allDocs.find((doc) => doc._raw.flattenedPath === pathFromSlugs)
if (!doc) return redirect('/docs/Basic use/Save and Paste')
return doc
}
export default function DocsPage({ params }: { params: { slug?: string[] } }) {
if (!params.slug) return redirect('/docs/Basic use/Save and Paste')
params.slug = params.slug?.map((slug) => decodeURI(slug))
const doc = getDocBySlugs(params.slug)
return (
<article className="min-h-screen pb-8 overflow-x-auto px-8 border-l">
<div className="flex mb-4 gap-1 items-center text-sm">
<p className="text-muted-foreground">{doc._raw.sourceFileDir}</p>
<MdKeyboardArrowRight className="text-muted-foreground" />
<p className="font-medium text-indigo-800 dark:bg-zinc-900 dark:text-indigo-600 bg-indigo-100 px-2 rounded-full">{doc.title}</p>
</div>
<Mdx code={doc?.body.code!} />
</article>
)
}
'use client'
import { usePathname } from 'next/navigation'
import { Doc, allDocs } from "@/.contentlayer/generated";
import Link from "next/link";
import { cn } from '@/lib/utils';
export default function DocsSideNav() {
const sortedArr = allDocs.sort((a, b) => a.sortNum - b.sortNum)
const path = decodeURI(usePathname())
const categorizedDocs = sortedArr.reduce((acc: { [key: Doc['_raw']['sourceFileDir']]: Doc[] }, doc) => {
const currCatContent = acc[doc._raw.sourceFileDir]
return {
...acc,
[doc._raw.sourceFileDir]: [...(currCatContent ? currCatContent : []), doc]
}
}, {})
return (
<div className="relative pr-6">
<div className='sticky top-[7.04rem] text-sm'>
{Object.entries(categorizedDocs).map(([cat, docs], i) => {
return (
<div key={i} className="mb-4">
<p className="text-foreground font-semibold mb-2">{cat}</p>
<div className="flex flex-col gap-1">
{docs.map((doc, j) => {
const isActive = path === `/docs/${doc._raw.flattenedPath}`
return <Link key={j} style={{ contain: "inline-size" }} href={`/docs/${doc._raw.flattenedPath}`} className={cn("ml-0 text-muted-foreground hover:text-indigo-700 dark:hover:text-indigo-600 transition-all hover:bg-indigo-50 py-1 px-2 rounded-md text-ellipsis whitespace-nowrap overflow-hidden dark:hover:bg-zinc-900", isActive ? "bg-indigo-50 dark:bg-zinc-900 dark:text-indigo-600 text-indigo-700" : "")}>{doc.title}</Link>
})}
</div>
</div>
)
})}
</div>
</div>
)
}
'use client'
import { usePathname } from 'next/navigation'
import { Doc, allDocs } from "@/.contentlayer/generated";
import Link from "next/link";
import { cn } from '@/lib/utils';
export default function DocsSideNav() {
const sortedArr = allDocs.sort((a, b) => a.sortNum - b.sortNum)
const path = decodeURI(usePathname())
const categorizedDocs = sortedArr.reduce((acc: { [key: Doc['_raw']['sourceFileDir']]: Doc[] }, doc) => {
const currCatContent = acc[doc._raw.sourceFileDir]
return {
...acc,
[doc._raw.sourceFileDir]: [...(currCatContent ? currCatContent : []), doc]
}
}, {})
return (
<div className="relative pr-6">
<div className='sticky top-[7.04rem] text-sm'>
{Object.entries(categorizedDocs).map(([cat, docs], i) => {
return (
<div key={i} className="mb-4">
<p className="text-foreground font-semibold mb-2">{cat}</p>
<div className="flex flex-col gap-1">
{docs.map((doc, j) => {
const isActive = path === `/docs/${doc._raw.flattenedPath}`
return <Link key={j} style={{ contain: "inline-size" }} href={`/docs/${doc._raw.flattenedPath}`} className={cn("ml-0 text-muted-foreground hover:text-indigo-700 dark:hover:text-indigo-600 transition-all hover:bg-indigo-50 py-1 px-2 rounded-md text-ellipsis whitespace-nowrap overflow-hidden dark:hover:bg-zinc-900", isActive ? "bg-indigo-50 dark:bg-zinc-900 dark:text-indigo-600 text-indigo-700" : "")}>{doc.title}</Link>
})}
</div>
</div>
)
})}
</div>
</div>
)
}
```mdx title="./docs/Included templates/contentlayer-next-styled-mdx-components.mdx"
---
title: contentlayer-next-styled-mdx-components
sortNum: 103
---
### contentlayer-next-styled-mdx-components
#### Pasted files structure
```bash
└── components
└── mdx-components.tsx1 directory, 1 file
```mdx title="./docs/Included templates/contentlayer-next-styled-mdx-components.mdx"
---
title: contentlayer-next-styled-mdx-components
sortNum: 103
---
### contentlayer-next-styled-mdx-components
#### Pasted files structure
```bash
└── components
└── mdx-components.tsx1 directory, 1 file
Files contents
'use client'
import { cn } from "@/lib/utils"
import { useMDXComponent } from "next-contentlayer/hooks"
import Image from "next/image"
import Link from "next/link"
import * as React from "react"
import toast from "react-hot-toast"
import { BsLink45Deg } from 'react-icons/bs'
import { FiBookOpen, FiCopy } from "react-icons/fi"
import { IoArrowForwardOutline } from 'react-icons/io5'
interface NextCardHolderProps {
cards: {
title: string
description: string
link: string
iconType?: 'arrow' | 'book'
}[]
}
function NextCardHolder({ cards }: NextCardHolderProps) {
return (
<div id="grid-card" className="grid grid-cols-2 gap-4 mt-6">
{cards.map(({ description, iconType = 'arrow', link, title }, index) => (
<Link href={link} key={index} className="flex flex-col border px-4 py-3 rounded-lg shadow-lg cursor-pointer">
<div className="flex flex-row-reverse justify-between gap-2">
<h3 className="text-lg font-semibold text-left">{title}</h3>
{iconType === 'arrow' && <IoArrowForwardOutline className="text-3xl" />}
{iconType === 'book' && <FiBookOpen className="text-3xl" />}
</div>
<p className="text-base text-left">{description}</p>
</Link>
))}
</div>
)
}
const components = {
h1: ({ className, ...props }: React.HTMLAttributes<HTMLHeadingElement>) => (
<h1
className={cn(
"mt-2 scroll-m-20 text-4xl font-bold tracking-tight",
className
)}
{...props}
/>
),
h2: ({ className, ...props }: React.HTMLAttributes<HTMLHeadingElement>) => (
<h2
className={cn(
"mt-10 scroll-m-20 border-b pb-1 text-3xl font-semibold tracking-tight first:mt-0",
className
)}
{...props}
/>
),
h3: ({ className, ...props }: React.HTMLAttributes<HTMLHeadingElement>) => (
<h3
className={cn(
"mt-8 scroll-m-20 text-2xl font-semibold tracking-tight",
className
)}
{...props}
/>
),
h4: ({ className, ...props }: React.HTMLAttributes<HTMLHeadingElement>) => (
<h4
className={cn(
"mt-8 scroll-m-20 text-xl font-semibold tracking-tight",
className
)}
{...props}
/>
),
h5: ({ className, ...props }: React.HTMLAttributes<HTMLHeadingElement>) => (
<h5
className={cn(
"mt-8 scroll-m-20 text-lg font-semibold tracking-tight",
className
)}
{...props}
/>
),
h6: ({ className, ...props }: React.HTMLAttributes<HTMLHeadingElement>) => (
<h6
className={cn(
"mt-8 scroll-m-20 text-base font-semibold tracking-tight",
className
)}
{...props}
/>
),
a: ({ className, ...props }: React.HTMLAttributes<HTMLAnchorElement>) => {
if (props['aria-label'] === "Link to section") {
return <a
className={cn("group flex items-center gap-1 relative", className)}
{...props}
>
<BsLink45Deg className="absolute -left-6 group-hover:visible invisible" />
{props.children}
</a>
}
return <a
className={cn("font-medium underline underline-offset-4", className)}
{...props}
/>
},
p: ({ className, ...props }: React.HTMLAttributes<HTMLParagraphElement>) => (
<p
className={cn("leading-7 [&:not(:first-child)]:mt-6", className)}
{...props}
/>
),
ul: ({ className, ...props }: React.HTMLAttributes<HTMLUListElement>) => (
<ul className={cn("my-6 ml-6 list-disc", className)} {...props} />
),
ol: ({ className, ...props }: React.HTMLAttributes<HTMLOListElement>) => (
<ol className={cn("my-6 ml-6 list-decimal", className)} {...props} />
),
li: ({ className, ...props }: React.HTMLAttributes<HTMLLIElement>) => (
<li className={cn("mt-2", className)} {...props} />
),
blockquote: ({ className, ...props }: React.HTMLAttributes<HTMLQuoteElement>) => (
<blockquote
className={cn(
"mt-6 border-l-2 pl-6 italic [&>*]:text-muted-foreground",
className
)}
{...props}
/>
),
img: ({
className,
alt,
...props
}: React.ImgHTMLAttributes<HTMLImageElement>) => (
// eslint-disable-next-line @next/next/no-img-element
<img className={cn("rounded-md border mt-4", className)} alt={alt} {...props} />
),
hr: ({ ...props }) => <hr className="my-4 md:my-8" {...props} />,
table: ({ className, ...props }: React.HTMLAttributes<HTMLTableElement>) => (
<div className="my-6 w-full overflow-y-auto">
<table className={cn("w-full", className)} {...props} />
</div>
),
tr: ({ className, ...props }: React.HTMLAttributes<HTMLTableRowElement>) => (
<tr
className={cn("m-0 border-t p-0 even:bg-muted", className)}
{...props}
/>
),
th: ({ className, ...props }: React.HTMLAttributes<HTMLTableCellElement>) => (
<th
className={cn(
"border px-4 py-2 text-left font-bold [&[align=center]]:text-center [&[align=right]]:text-right",
className
)}
{...props}
/>
),
td: ({ className, ...props }: React.HTMLAttributes<HTMLTableCellElement>) => (
<td
className={cn(
"border px-4 py-2 text-left [&[align=center]]:text-center [&[align=right]]:text-right",
className
)}
{...props}
/>
),
pre: ({ className, ...props }: React.HTMLAttributes<HTMLPreElement>) => {
// @ts-ignore
if (props['data-language'] === 'command') return <pre
className={cn(
"mb-4 mt-6 overflow-x-auto rounded-lg bg-indigo-50 dark:bg-zinc-900 dark:text-zinc-50",
className
)}
{...props}
/>
return <pre
className={cn(
"mb-4 mt-6 overflow-x-auto rounded-lg bg-indigo-50 py-4 dark:bg-zinc-900 dark:text-zinc-50",
className
)}
{...props}
/>
},
code: ({ className, ...props }: React.HTMLAttributes<HTMLElement>) => {
// @ts-ignore
if (props['data-language'] === 'command') return <code
className={cn(
"relative rounded px-[1rem] py-[0.5rem] font-mono bg-indigo-50 dark:bg-zinc-900",
className
)}
{...props}
>
<FiCopy onClick={() => toast.success('copied! 📝')} className="absolute top-1/2 -translate-y-1/2 right-1 hover:bg-indigo-200 p-2 rounded-md box-content transition-all cursor-pointer" />
{props.children}
</code>
return <code
className={cn(
"relative rounded px-[0.3rem] py-[0.2rem] font-mono text-sm bg-indigo-50 dark:bg-zinc-900",
className
)}
{...props}
/>
},
Image,
NextCardHolder
}
interface MdxProps {
code: string
}
export function Mdx({ code }: MdxProps) {
const Component = useMDXComponent(code)
return (
<div className="mdx">
<Component components={components} />
</div>
)
}
'use client'
import { cn } from "@/lib/utils"
import { useMDXComponent } from "next-contentlayer/hooks"
import Image from "next/image"
import Link from "next/link"
import * as React from "react"
import toast from "react-hot-toast"
import { BsLink45Deg } from 'react-icons/bs'
import { FiBookOpen, FiCopy } from "react-icons/fi"
import { IoArrowForwardOutline } from 'react-icons/io5'
interface NextCardHolderProps {
cards: {
title: string
description: string
link: string
iconType?: 'arrow' | 'book'
}[]
}
function NextCardHolder({ cards }: NextCardHolderProps) {
return (
<div id="grid-card" className="grid grid-cols-2 gap-4 mt-6">
{cards.map(({ description, iconType = 'arrow', link, title }, index) => (
<Link href={link} key={index} className="flex flex-col border px-4 py-3 rounded-lg shadow-lg cursor-pointer">
<div className="flex flex-row-reverse justify-between gap-2">
<h3 className="text-lg font-semibold text-left">{title}</h3>
{iconType === 'arrow' && <IoArrowForwardOutline className="text-3xl" />}
{iconType === 'book' && <FiBookOpen className="text-3xl" />}
</div>
<p className="text-base text-left">{description}</p>
</Link>
))}
</div>
)
}
const components = {
h1: ({ className, ...props }: React.HTMLAttributes<HTMLHeadingElement>) => (
<h1
className={cn(
"mt-2 scroll-m-20 text-4xl font-bold tracking-tight",
className
)}
{...props}
/>
),
h2: ({ className, ...props }: React.HTMLAttributes<HTMLHeadingElement>) => (
<h2
className={cn(
"mt-10 scroll-m-20 border-b pb-1 text-3xl font-semibold tracking-tight first:mt-0",
className
)}
{...props}
/>
),
h3: ({ className, ...props }: React.HTMLAttributes<HTMLHeadingElement>) => (
<h3
className={cn(
"mt-8 scroll-m-20 text-2xl font-semibold tracking-tight",
className
)}
{...props}
/>
),
h4: ({ className, ...props }: React.HTMLAttributes<HTMLHeadingElement>) => (
<h4
className={cn(
"mt-8 scroll-m-20 text-xl font-semibold tracking-tight",
className
)}
{...props}
/>
),
h5: ({ className, ...props }: React.HTMLAttributes<HTMLHeadingElement>) => (
<h5
className={cn(
"mt-8 scroll-m-20 text-lg font-semibold tracking-tight",
className
)}
{...props}
/>
),
h6: ({ className, ...props }: React.HTMLAttributes<HTMLHeadingElement>) => (
<h6
className={cn(
"mt-8 scroll-m-20 text-base font-semibold tracking-tight",
className
)}
{...props}
/>
),
a: ({ className, ...props }: React.HTMLAttributes<HTMLAnchorElement>) => {
if (props['aria-label'] === "Link to section") {
return <a
className={cn("group flex items-center gap-1 relative", className)}
{...props}
>
<BsLink45Deg className="absolute -left-6 group-hover:visible invisible" />
{props.children}
</a>
}
return <a
className={cn("font-medium underline underline-offset-4", className)}
{...props}
/>
},
p: ({ className, ...props }: React.HTMLAttributes<HTMLParagraphElement>) => (
<p
className={cn("leading-7 [&:not(:first-child)]:mt-6", className)}
{...props}
/>
),
ul: ({ className, ...props }: React.HTMLAttributes<HTMLUListElement>) => (
<ul className={cn("my-6 ml-6 list-disc", className)} {...props} />
),
ol: ({ className, ...props }: React.HTMLAttributes<HTMLOListElement>) => (
<ol className={cn("my-6 ml-6 list-decimal", className)} {...props} />
),
li: ({ className, ...props }: React.HTMLAttributes<HTMLLIElement>) => (
<li className={cn("mt-2", className)} {...props} />
),
blockquote: ({ className, ...props }: React.HTMLAttributes<HTMLQuoteElement>) => (
<blockquote
className={cn(
"mt-6 border-l-2 pl-6 italic [&>*]:text-muted-foreground",
className
)}
{...props}
/>
),
img: ({
className,
alt,
...props
}: React.ImgHTMLAttributes<HTMLImageElement>) => (
// eslint-disable-next-line @next/next/no-img-element
<img className={cn("rounded-md border mt-4", className)} alt={alt} {...props} />
),
hr: ({ ...props }) => <hr className="my-4 md:my-8" {...props} />,
table: ({ className, ...props }: React.HTMLAttributes<HTMLTableElement>) => (
<div className="my-6 w-full overflow-y-auto">
<table className={cn("w-full", className)} {...props} />
</div>
),
tr: ({ className, ...props }: React.HTMLAttributes<HTMLTableRowElement>) => (
<tr
className={cn("m-0 border-t p-0 even:bg-muted", className)}
{...props}
/>
),
th: ({ className, ...props }: React.HTMLAttributes<HTMLTableCellElement>) => (
<th
className={cn(
"border px-4 py-2 text-left font-bold [&[align=center]]:text-center [&[align=right]]:text-right",
className
)}
{...props}
/>
),
td: ({ className, ...props }: React.HTMLAttributes<HTMLTableCellElement>) => (
<td
className={cn(
"border px-4 py-2 text-left [&[align=center]]:text-center [&[align=right]]:text-right",
className
)}
{...props}
/>
),
pre: ({ className, ...props }: React.HTMLAttributes<HTMLPreElement>) => {
// @ts-ignore
if (props['data-language'] === 'command') return <pre
className={cn(
"mb-4 mt-6 overflow-x-auto rounded-lg bg-indigo-50 dark:bg-zinc-900 dark:text-zinc-50",
className
)}
{...props}
/>
return <pre
className={cn(
"mb-4 mt-6 overflow-x-auto rounded-lg bg-indigo-50 py-4 dark:bg-zinc-900 dark:text-zinc-50",
className
)}
{...props}
/>
},
code: ({ className, ...props }: React.HTMLAttributes<HTMLElement>) => {
// @ts-ignore
if (props['data-language'] === 'command') return <code
className={cn(
"relative rounded px-[1rem] py-[0.5rem] font-mono bg-indigo-50 dark:bg-zinc-900",
className
)}
{...props}
>
<FiCopy onClick={() => toast.success('copied! 📝')} className="absolute top-1/2 -translate-y-1/2 right-1 hover:bg-indigo-200 p-2 rounded-md box-content transition-all cursor-pointer" />
{props.children}
</code>
return <code
className={cn(
"relative rounded px-[0.3rem] py-[0.2rem] font-mono text-sm bg-indigo-50 dark:bg-zinc-900",
className
)}
{...props}
/>
},
Image,
NextCardHolder
}
interface MdxProps {
code: string
}
export function Mdx({ code }: MdxProps) {
const Component = useMDXComponent(code)
return (
<div className="mdx">
<Component components={components} />
</div>
)
}
```mdx title="./docs/Included templates/next-redux-ts.mdx"
---
title: next-redux-ts
sortNum: 104
---
### next-redux-ts
Typescript redux toolkit with skeleton createApi, createSlice and TS redux hooks.
#### Pasted files structure
```bash
├── features
│ └── counterSlice.ts
├── hooks.ts
├── provider.tsx
├── services
│ └── userApi.ts
└── store.ts
```mdx title="./docs/Included templates/next-redux-ts.mdx"
---
title: next-redux-ts
sortNum: 104
---
### next-redux-ts
Typescript redux toolkit with skeleton createApi, createSlice and TS redux hooks.
#### Pasted files structure
```bash
├── features
│ └── counterSlice.ts
├── hooks.ts
├── provider.tsx
├── services
│ └── userApi.ts
└── store.ts
Files contents
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
type CounterState = {
value: number;
};
const initialState = {
value: 0,
} as CounterState;
export const counter = createSlice({
name: "counter",
initialState,
reducers: {
reset: () => initialState,
increment: (state) => {
state.value += 1;
},
incrementByAmount: (state, action: PayloadAction<number>) => {
state.value += action.payload;
},
},
});
export const {
increment,
incrementByAmount,
} = counter.actions;
export default counter.reducer;
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
type CounterState = {
value: number;
};
const initialState = {
value: 0,
} as CounterState;
export const counter = createSlice({
name: "counter",
initialState,
reducers: {
reset: () => initialState,
increment: (state) => {
state.value += 1;
},
incrementByAmount: (state, action: PayloadAction<number>) => {
state.value += action.payload;
},
},
});
export const {
increment,
incrementByAmount,
} = counter.actions;
export default counter.reducer;
import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";
import type { RootState, AppDispatch } from "./store";
export const useAppDispatch = () => useDispatch<AppDispatch>();
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";
import type { RootState, AppDispatch } from "./store";
export const useAppDispatch = () => useDispatch<AppDispatch>();
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
"use client";
import { store } from "./store";
import { Provider } from "react-redux";
export function Providers({ children }: { children: React.ReactNode }) {
return <Provider store={store}>{children}</Provider>;
}
"use client";
import { store } from "./store";
import { Provider } from "react-redux";
export function Providers({ children }: { children: React.ReactNode }) {
return <Provider store={store}>{children}</Provider>;
}
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
type User = {
id: number;
name: string;
email: number;
};
export const userApi = createApi({
reducerPath: "userApi",
refetchOnFocus: true,
baseQuery: fetchBaseQuery({
baseUrl: "https://your-api-url.com/",
}),
endpoints: (builder) => ({
getUsers: builder.query<User[], null>({
query: () => "users",
}),
getUserById: builder.query<User, { id: string }>({
query: ({ id }) => `users/${id}`,
}),
}),
});
export const { useGetUsersQuery, useGetUserByIdQuery } = userApi;
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
type User = {
id: number;
name: string;
email: number;
};
export const userApi = createApi({
reducerPath: "userApi",
refetchOnFocus: true,
baseQuery: fetchBaseQuery({
baseUrl: "https://your-api-url.com/",
}),
endpoints: (builder) => ({
getUsers: builder.query<User[], null>({
query: () => "users",
}),
getUserById: builder.query<User, { id: string }>({
query: ({ id }) => `users/${id}`,
}),
}),
});
export const { useGetUsersQuery, useGetUserByIdQuery } = userApi;
import { configureStore } from "@reduxjs/toolkit";
import counterReducer from "./features/counterSlice";
import { userApi } from "./services/userApi";
import { setupListeners } from "@reduxjs/toolkit/dist/query";
export const store = configureStore({
reducer: {
counterReducer,
[userApi.reducerPath]: userApi.reducer,
},
devTools: process.env.NODE_ENV !== "production",
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({}).concat([userApi.middleware]),
});
setupListeners(store.dispatch);
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
import { configureStore } from "@reduxjs/toolkit";
import counterReducer from "./features/counterSlice";
import { userApi } from "./services/userApi";
import { setupListeners } from "@reduxjs/toolkit/dist/query";
export const store = configureStore({
reducer: {
counterReducer,
[userApi.reducerPath]: userApi.reducer,
},
devTools: process.env.NODE_ENV !== "production",
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({}).concat([userApi.middleware]),
});
setupListeners(store.dispatch);
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
```mdx title="./docs/Included templates/next-shad-darkmode.mdx"
---
title: next-shad-darkmode
sortNum: 105
---
### next-shad-darkmode
#### Pasted files structure
```bash
└── components
├── ThemeProvider.tsx
└── ui
└── ModeToggle.tsx
```mdx title="./docs/Included templates/next-shad-darkmode.mdx"
---
title: next-shad-darkmode
sortNum: 105
---
### next-shad-darkmode
#### Pasted files structure
```bash
└── components
├── ThemeProvider.tsx
└── ui
└── ModeToggle.tsx
Files contents
'use client'
import { ThemeProvider as NextThemeProvider } from "next-themes"
export default function ThemeProvider({ children }: { children: React.ReactNode }) {
return (
<NextThemeProvider attribute="class" defaultTheme="light" enableSystem>
{children}
</NextThemeProvider>
)
}
'use client'
import { ThemeProvider as NextThemeProvider } from "next-themes"
export default function ThemeProvider({ children }: { children: React.ReactNode }) {
return (
<NextThemeProvider attribute="class" defaultTheme="light" enableSystem>
{children}
</NextThemeProvider>
)
}
"use client"
import * as React from "react"
import { Moon, Sun } from "lucide-react"
import { useTheme } from "next-themes"
import { Button } from "@/components/ui/button"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
export function ModeToggle() {
const { setTheme } = useTheme()
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline" size="icon">
<Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
<Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
<span className="sr-only">Toggle theme</span>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem onClick={() => setTheme("light")}>
Light
</DropdownMenuItem>
<DropdownMenuItem onClick={() => setTheme("dark")}>
Dark
</DropdownMenuItem>
<DropdownMenuItem onClick={() => setTheme("system")}>
System
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)
}
"use client"
import * as React from "react"
import { Moon, Sun } from "lucide-react"
import { useTheme } from "next-themes"
import { Button } from "@/components/ui/button"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
export function ModeToggle() {
const { setTheme } = useTheme()
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline" size="icon">
<Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
<Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
<span className="sr-only">Toggle theme</span>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem onClick={() => setTheme("light")}>
Light
</DropdownMenuItem>
<DropdownMenuItem onClick={() => setTheme("dark")}>
Dark
</DropdownMenuItem>
<DropdownMenuItem onClick={() => setTheme("system")}>
System
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)
}
```mdx title="./docs/Included templates/next13-app-auth-paste-from-root.mdx"
---
title: next13-app-auth-paste-from-root
sortNum: 106
---
### next13-app-auth-paste-from-root
Adds basic auth.js with Github provider, React provider component and exmaple .env file to TS nextjs13 with app router. Must be paste in root folder, where app/ dir is located.
#### Pasted files structure
```bash
├── app
│ └── api
│ └── auth
│ └── [...nextauth]
│ └── route.ts
└── components
└── AuthProvider.tsx
```mdx title="./docs/Included templates/next13-app-auth-paste-from-root.mdx"
---
title: next13-app-auth-paste-from-root
sortNum: 106
---
### next13-app-auth-paste-from-root
Adds basic auth.js with Github provider, React provider component and exmaple .env file to TS nextjs13 with app router. Must be paste in root folder, where app/ dir is located.
#### Pasted files structure
```bash
├── app
│ └── api
│ └── auth
│ └── [...nextauth]
│ └── route.ts
└── components
└── AuthProvider.tsx
Files contents
GITHUB_ID=9c7fd0feb8bb492b5082
GITHUB_SECRET=1086b7d5d18b020be74fd00a034a4d19be4380ae
NEXTAUTH_SECRET=LUIt4Y+LigEa/rXhJpbLqloJ2pbHUK271WUV5yLAZyI=
GITHUB_ID=9c7fd0feb8bb492b5082
GITHUB_SECRET=1086b7d5d18b020be74fd00a034a4d19be4380ae
NEXTAUTH_SECRET=LUIt4Y+LigEa/rXhJpbLqloJ2pbHUK271WUV5yLAZyI=
import NextAuth, { AuthOptions } from "next-auth"
import GithubProvider from "next-auth/providers/github"
export const authOptions: AuthOptions = {
// Configure one or more authentication providers
providers: [
GithubProvider({
clientId: process.env.GITHUB_ID!,
clientSecret: process.env.GITHUB_SECRET!,
}),
// ...add more providers here
],
}
const handler = NextAuth(authOptions)
export { handler as GET, handler as POST }
import NextAuth, { AuthOptions } from "next-auth"
import GithubProvider from "next-auth/providers/github"
export const authOptions: AuthOptions = {
// Configure one or more authentication providers
providers: [
GithubProvider({
clientId: process.env.GITHUB_ID!,
clientSecret: process.env.GITHUB_SECRET!,
}),
// ...add more providers here
],
}
const handler = NextAuth(authOptions)
export { handler as GET, handler as POST }
'use client'
import { SessionProvider } from "next-auth/react";
export default function Providers({ children }: { children: React.ReactNode }) {
return (
<SessionProvider>
{children}
</SessionProvider>
)
}
'use client'
import { SessionProvider } from "next-auth/react";
export default function Providers({ children }: { children: React.ReactNode }) {
return (
<SessionProvider>
{children}
</SessionProvider>
)
}
```mdx title="./docs/Included templates/redux-ts.mdx"
---
title: "next-redux-ts"
sortNum: 4
---
### Redux Toolkit Typescript template for NextJS 13.
Consists of basic RTK setup with Typescript.
- Typesafe hooks
- Store setup
- Basic slice setup
- Basic API setup
#### Pasted files straucture
```bash
├── features
│ └── counterSlice.ts
├── services
│ └── userApi.ts
├── store.ts
├── hooks.ts
```mdx title="./docs/Included templates/redux-ts.mdx"
---
title: "next-redux-ts"
sortNum: 4
---
### Redux Toolkit Typescript template for NextJS 13.
Consists of basic RTK setup with Typescript.
- Typesafe hooks
- Store setup
- Basic slice setup
- Basic API setup
#### Pasted files straucture
```bash
├── features
│ └── counterSlice.ts
├── services
│ └── userApi.ts
├── store.ts
├── hooks.ts
Files contents
import { configureStore } from "@reduxjs/toolkit";
import counterReducer from "./features/counterSlice";
import { userApi } from "./services/userApi";
import { setupListeners } from "@reduxjs/toolkit/dist/query";
export const store = configureStore({
reducer: {
counterReducer,
[userApi.reducerPath]: userApi.reducer,
},
devTools: process.env.NODE_ENV !== "production",
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({}).concat([userApi.middleware]),
});
setupListeners(store.dispatch);
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
import { configureStore } from "@reduxjs/toolkit";
import counterReducer from "./features/counterSlice";
import { userApi } from "./services/userApi";
import { setupListeners } from "@reduxjs/toolkit/dist/query";
export const store = configureStore({
reducer: {
counterReducer,
[userApi.reducerPath]: userApi.reducer,
},
devTools: process.env.NODE_ENV !== "production",
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({}).concat([userApi.middleware]),
});
setupListeners(store.dispatch);
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
type User = {
id: number;
name: string;
email: number;
};
export const userApi = createApi({
reducerPath: "userApi",
refetchOnFocus: true,
baseQuery: fetchBaseQuery({
baseUrl: "https://your-api-url.com/",
}),
endpoints: (builder) => ({
getUsers: builder.query<User[], null>({
query: () => "users",
}),
getUserById: builder.query<User, { id: string }>({
query: ({ id }) => `users/${id}`,
}),
}),
});
export const { useGetUsersQuery, useGetUserByIdQuery } = userApi;
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
type User = {
id: number;
name: string;
email: number;
};
export const userApi = createApi({
reducerPath: "userApi",
refetchOnFocus: true,
baseQuery: fetchBaseQuery({
baseUrl: "https://your-api-url.com/",
}),
endpoints: (builder) => ({
getUsers: builder.query<User[], null>({
query: () => "users",
}),
getUserById: builder.query<User, { id: string }>({
query: ({ id }) => `users/${id}`,
}),
}),
});
export const { useGetUsersQuery, useGetUserByIdQuery } = userApi;
import { configureStore } from "@reduxjs/toolkit";
import counterReducer from "./features/counterSlice";
import { userApi } from "./services/userApi";
import { setupListeners } from "@reduxjs/toolkit/dist/query";
export const store = configureStore({
reducer: {
counterReducer,
[userApi.reducerPath]: userApi.reducer,
},
devTools: process.env.NODE_ENV !== "production",
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({}).concat([userApi.middleware]),
});
setupListeners(store.dispatch);
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
import { configureStore } from "@reduxjs/toolkit";
import counterReducer from "./features/counterSlice";
import { userApi } from "./services/userApi";
import { setupListeners } from "@reduxjs/toolkit/dist/query";
export const store = configureStore({
reducer: {
counterReducer,
[userApi.reducerPath]: userApi.reducer,
},
devTools: process.env.NODE_ENV !== "production",
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({}).concat([userApi.middleware]),
});
setupListeners(store.dispatch);
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";
import type { RootState, AppDispatch } from "./store";
export const useAppDispatch = () => useDispatch<AppDispatch>();
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";
import type { RootState, AppDispatch } from "./store";
export const useAppDispatch = () => useDispatch<AppDispatch>();
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
```css title="./styles/docs.css"
div[data-rehype-pretty-code-title] {
margin-top: 0;
background-color: #eef2ff;
margin-top: 1.5rem;
border-top-right-radius: 0.5rem;
border-top-left-radius: 0.5rem;
font-size: 0.875rem;
padding: 0.5rem 0.5rem;
border-bottom: 1px solid #dfe2f5;
font-weight: 500;
&+pre {
margin-top: 0;
padding-top: 0.5rem;
border-top-left-radius: 0;
border-top-right-radius: 0;
}
}
.dark {
& div[data-rehype-pretty-code-title] {
margin-top: 0;
background-color: #18181b;
margin-top: 1.5rem;
border-top-right-radius: 0.5rem;
border-top-left-radius: 0.5rem;
font-size: 0.875rem;
padding: 0.5rem 0.5rem;
border-bottom: 1px solid #27272a;
font-weight: 500;
&+pre {
margin-top: 0;
padding-top: 0.5rem;
border-top-left-radius: 0;
border-top-right-radius: 0;
}
}
& pre::-webkit-scrollbar-thumb {
background-color: #27272a;
}
& pre::-webkit-scrollbar-thumb:hover {
background-color: #3f3f46;
}
& div[data-rehype-pretty-code-fragment] {
& [data-theme="light"] {
display: none;
}
}
}
.light {
div[data-rehype-pretty-code-fragment] {
& [data-theme="dark"] {
display: none;
}
}
}
```css title="./styles/docs.css"
div[data-rehype-pretty-code-title] {
margin-top: 0;
background-color: #eef2ff;
margin-top: 1.5rem;
border-top-right-radius: 0.5rem;
border-top-left-radius: 0.5rem;
font-size: 0.875rem;
padding: 0.5rem 0.5rem;
border-bottom: 1px solid #dfe2f5;
font-weight: 500;
&+pre {
margin-top: 0;
padding-top: 0.5rem;
border-top-left-radius: 0;
border-top-right-radius: 0;
}
}
.dark {
& div[data-rehype-pretty-code-title] {
margin-top: 0;
background-color: #18181b;
margin-top: 1.5rem;
border-top-right-radius: 0.5rem;
border-top-left-radius: 0.5rem;
font-size: 0.875rem;
padding: 0.5rem 0.5rem;
border-bottom: 1px solid #27272a;
font-weight: 500;
&+pre {
margin-top: 0;
padding-top: 0.5rem;
border-top-left-radius: 0;
border-top-right-radius: 0;
}
}
& pre::-webkit-scrollbar-thumb {
background-color: #27272a;
}
& pre::-webkit-scrollbar-thumb:hover {
background-color: #3f3f46;
}
& div[data-rehype-pretty-code-fragment] {
& [data-theme="light"] {
display: none;
}
}
}
.light {
div[data-rehype-pretty-code-fragment] {
& [data-theme="dark"] {
display: none;
}
}
}